# -*- coding=utf-8

# 需要安装的依赖
# werobot boto3
# 函数计算执行
# ```bash
# pip install boto3 -t . 
# ```

"""
这是 Obsidian 存储到云端后，为了安全等目的封装 api 。支持 S3 
"""
import boto3
from botocore.errorfactory import ClientError
import requests
import datetime
import configparser
from botocore.config import Config

config = configparser.ConfigParser()
config.read('config.ini', encoding="utf-8")
timeFix = config.getint('global','TimeFix')

def timeFmt(timeFrom: str,dayNum: int = 0,):
    """计算机时区 +8 time zone 时间格式化 dayNum = 0 今天 -1 昨天 timeFrom eg: %Y-%m-%d %Y%m%d%H%M%S"""
    return (datetime.datetime.now() + datetime.timedelta(days=dayNum, hours=timeFix)).strftime(timeFrom)

obsettings_default = {
    "daily_dir": "daily/", 
    "daily_time_fmt": "%Y-%m-%d", 
    "zk_dir": "ZK/",
    "zk_time_fmt": "%Y%m%d%H%M",
    "daily_attachment_dir": "attachment/",
    "daily_attachment_dir_time_fmt": "%Y%m/",
    "zk_attachment_dir": "attachment/",
    "zk_attachment_dir_time_fmt": "%Y%m/",
    "other_attachment_dir": "attachment/",
    "other_attachment_dir_time_fmt": "%Y%m",
    }

class ObS3(object):
    def __init__(self, s3config: dict, bucket: str, obsettings: dict = obsettings_default):
        self.client = boto3.client( 's3',
            aws_access_key_id= s3config['SecretId'],
            aws_secret_access_key= s3config['SecretKey'], 
            use_ssl=True, region_name=s3config['Region'], 
            endpoint_url='https://' + s3config['Endpoint'],
            config=Config(s3={"addressing_style": "virtual"}),
        )
        self.bucket = bucket
        self.obsettings = obsettings_default
        self.obsettings.update(obsettings)
    

    def info(self):
        print(self.daily_file_key())
        print(self.daily_attachment_file_dir()+"test.jpg")
        print(self.zk_file_key())
        print(self.obsettings)
    
    def daily_file_key(self):
        """eg: daily/2000-01-01.md"""
        return self.obsettings['daily_dir'] + timeFmt(self.obsettings['daily_time_fmt']) + '.md'
    
    def daily_attachment_file_dir(self):
        """eg: daily/attachment/202201"""
        return self.obsettings['daily_dir'] + self.obsettings['daily_attachment_dir'] + timeFmt(self.obsettings['daily_attachment_dir_time_fmt'])
    
    def zk_file_key(self):
        """eg: ZK/201201211800.md"""
        return self.obsettings['zk_dir'] + timeFmt(self.obsettings['zk_time_fmt']) + '.md'
    
    def check(self,file_key: str):
        """判断是否存在该文件, 参数 文件key eg: check('daily/20220101.md')"""
        try:
            self.client.head_object(Bucket=self.bucket,Key=file_key)
        except ClientError:
            return False
        return True

    def get(self, text_file_key: str):
        """获取文件,仅限文本。有判断存在。 Only plain/text can use this. return utf-8 str"""
        if self.check(text_file_key) == True:
            response = self.client.get_object(Bucket=self.bucket, Key=text_file_key)
            return response["Body"]._raw_stream.read().decode("utf-8")
        else:
            return "No Such File: " + text_file_key

    def get_object(self, file_key: str):
        """获取文件return bytes"""
        response = self.client.get_object(Bucket=self.bucket, Key=file_key)
        return response["Body"]._raw_stream.read()

    def store(self, file_key: str, file_bytes: bytes):
        """直接上传存储,可能覆盖"""
        response = self.client.put_object(Bucket=self.bucket, Body=file_bytes, Key=file_key)
        return response["ETag"]

    def append(self, file_key: str, text: str):
        """有该文件则增添text 无该文件则新建并添加"""
        if self.check(file_key) == True:
            response = self.client.get_object(Bucket=self.bucket, Key=file_key)
            str1 = response["Body"]._raw_stream.read().decode("utf-8")
            btyes = bytes(str1 + text, encoding="utf8")
        else:
            btyes = bytes(text, encoding="utf8")
        response_sum = self.client.put_object(Bucket=self.bucket, Body=btyes, Key=file_key)
        return response_sum["ETag"]

    def append_daily(self, text: str):
        """daily 增加str内容"""
        return self.append( self.daily_file_key(), text)
    
    def append_memos_in_daily(self,text: str):
        """daily 以 memos 格式增加内容"""
        todo = "todo"
        if todo in text:
            text = timeFmt("\n- [ ] %H:%M ") + text
        else:
            text = timeFmt("\n- %H:%M ") + text
        return self.append(self.daily_file_key(), text)


    def store_by_url(self, file_key, file_url: str):
        """传入 http url 下载并按照 file_key 存储"""
        file = requests.get(file_url).content
        return self.store(file_key, file)

    def today_daily(self):
        """eg: today_daily() -> return daily/2022-1-1.md 文件内容 str"""
        return self.get(self.daily_file_key())

    def today_daily_json(self):
        """dailys dict list"""
        serverTime = timeFmt("%Y%m%d%H%M")
        return {
            "serverTime": serverTime,
            "date": timeFmt("%Y-%m-%d"),
            "data": self.get(self.daily_file_key()),
        }

    def recent_days_daily(self):
        """3 days Daily dict list"""
        serverTime = timeFmt("%Y%m%d%H%M")
        tem_list = []
        for i in range(-2, 1):  # -2 -1 0
            tem_list.append(
                {
                    "serverTime": serverTime,
                    "date": timeFmt("%Y-%m-%d",i),
                    "data": self.get(self.obsettings['daily_dir'] + timeFmt(self.obsettings['daily_time_fmt'],i) + ".md"),
                }
            )
        return tem_list

    def list(self):
        """MaxKeys 1000 简单 list 支持1000以内文件数量列出"""
        response = self.client.list_objects(Bucket=self.bucket)
        r_list = []
        if "Contents" in response:
            for content in response["Contents"]:
                r_list.append(content["Key"])
        return r_list
    
    def tem_url(self,file_key: str,expiresIn:int = 300) -> str:
        """ 生成临时访问 url 目的是用于图片链接访问"""
        return self.client.generate_presigned_url(ClientMethod='get_object',
        Params={ 'Bucket': self.bucket,'Key': file_key },
        ExpiresIn = expiresIn ) # 300s 过期

# 相关信息 与 测试代码

# S3Config = {
#     'Endpoint': 'cos.ap-beijing.myqcloud.com',
#     'Region': 'ap-beijing',
#     'SecretId' : 'xxxxxxxxxxxxxxxxxxxxxx',
#     'SecretKey': 'xxxxxxxxxxxxxxxxxxxxxx'
# }
# bucket = "obsidian-0123456789"

# obset = { 'daily_dir': '日志/','daily_attachment_dir': '附件/'}
# client = ObS3(config, bucket ,obset)
# client.info()
# print(client.get('支持类文件/test.md'))
# print(client.today_daily())
# client.append_daily("一行内容")
# client.append_memos_in_daily("这是一条 memeos")
# # client.store_by_url("附件/demo.jpg","https://abc.com/some.jpg")
# client.store(client.daily_file_key(),bytes('内容')) # 覆盖上传
# client.append('支持类文件/test.md','+++') # 增加三个+